<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Register A Callback To Handle SQLITE_BUSY Errors</title>
<style type="text/css">
body {
    margin: auto;
    font-family: Verdana, sans-serif;
    padding: 8px 1%;
}

a { color: #044a64 }
a:visited { color: #734559 }

.logo { position:absolute; margin:3px; }
.tagline {
  float:right;
  text-align:right;
  font-style:italic;
  width:300px;
  margin:12px;
  margin-top:58px;
}

.toolbar {
  text-align: center;
  line-height: 1.6em;
  margin: 0;
  padding: 0px 8px;
}
.toolbar a { color: white; text-decoration: none; padding: 6px 12px; }
.toolbar a:visited { color: white; }
.toolbar a:hover { color: #044a64; background: white; }

.content    { margin: 5%; }
.content dt { font-weight:bold; }
.content dd { margin-bottom: 25px; margin-left:20%; }
.content ul { padding:0px; padding-left: 15px; margin:0px; }

/* rounded corners */
.se  { background: url(../images/se.gif) 100% 100% no-repeat #044a64}
.sw  { background: url(../images/sw.gif) 0% 100% no-repeat }
.ne  { background: url(../images/ne.gif) 100% 0% no-repeat }
.nw  { background: url(../images/nw.gif) 0% 0% no-repeat }

/* Things for "fancyformat" documents start here. */
.fancy img+p {font-style:italic}
.fancy .codeblock i { color: darkblue; }
.fancy h1,.fancy h2,.fancy h3,.fancy h4 {font-weight:normal;color:#044a64}
.fancy h2 { margin-left: 10px }
.fancy h3 { margin-left: 20px }
.fancy h4 { margin-left: 30px }
.fancy th {white-space:nowrap;text-align:left;border-bottom:solid 1px #444}
.fancy th, .fancy td {padding: 0.2em 1ex; vertical-align:top}
.fancy #toc a        { color: darkblue ; text-decoration: none }
.fancy .todo         { color: #AA3333 ; font-style : italic }
.fancy .todo:before  { content: 'TODO:' }
.fancy p.todo        { border: solid #AA3333 1px; padding: 1ex }
.fancy img { display:block; }
.fancy :link:hover, .fancy :visited:hover { background: wheat }
.fancy p,.fancy ul,.fancy ol { margin: 1em 5ex }
.fancy li p { margin: 1em 0 }
/* End of "fancyformat" specific rules. */

</style>
  
</head>
<body>
<div><!-- container div to satisfy validator -->

<a href="../index.html">
<img class="logo" src="../images/sqlite370_banner.gif" alt="SQLite Logo"
 border="0"></a>
<div><!-- IE hack to prevent disappearing logo--></div>
<div class="tagline">Small. Fast. Reliable.<br>Choose any three.</div>

<table width=100% style="clear:both"><tr><td>
  <div class="se"><div class="sw"><div class="ne"><div class="nw">
  <table width=100% style="padding:0;margin:0;cell-spacing:0"><tr>
  <td width=100%>
  <div class="toolbar">
    <a href="../about.html">About</a>
    <a href="../sitemap.html">Sitemap</a>
    <a href="../docs.html">Documentation</a>
    <a href="../download.html">Download</a>
    <a href="../copyright.html">License</a>
    <a href="../news.html">News</a>
    <a href="../support.html">Support</a>
  </div>
<script>
  gMsg = "Search SQLite Docs..."
  function entersearch() {
    var q = document.getElementById("q");
    if( q.value == gMsg ) { q.value = "" }
    q.style.color = "black"
    q.style.fontStyle = "normal"
  }
  function leavesearch() {
    var q = document.getElementById("q");
    if( q.value == "" ) { 
      q.value = gMsg
      q.style.color = "#044a64"
      q.style.fontStyle = "italic"
    }
  }
</script>
<td>
    <div style="padding:0 1em 0px 0;white-space:nowrap">
    <form name=f method="GET" action="http://www.sqlite.org/search">
      <input id=q name=q type=text
       onfocus="entersearch()" onblur="leavesearch()" style="width:24ex;padding:1px 1ex; border:solid white 1px; font-size:0.9em ; font-style:italic;color:#044a64;" value="Search SQLite Docs...">
      <input type=submit value="Go" style="border:solid white 1px;background-color:#044a64;color:white;font-size:0.9em;padding:0 1ex">
    </form>
    </div>
  </table>
</div></div></div></div>
</td></tr></table>
<div class=startsearch></div>
  
<a href="intro.html"><h2>SQLite C Interface</h2></a><h2>Register A Callback To Handle SQLITE_BUSY Errors</h2><blockquote><pre>int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
</pre></blockquote><p>
This routine sets a callback function that might be invoked whenever
an attempt is made to open a database table that another thread
or process has locked.</p>

<p>If the busy callback is NULL, then <a href="../c3ref/c_abort.html">SQLITE_BUSY</a> or <a href="../c3ref/c_abort_rollback.html">SQLITE_IOERR_BLOCKED</a>
is returned immediately upon encountering the lock.  If the busy callback
is not NULL, then the callback might be invoked with two arguments.</p>

<p>The first argument to the busy handler is a copy of the void* pointer which
is the third argument to sqlite3_busy_handler().  The second argument to
the busy handler callback is the number of times that the busy handler has
been invoked for this locking event.  If the
busy callback returns 0, then no additional attempts are made to
access the database and <a href="../c3ref/c_abort.html">SQLITE_BUSY</a> or <a href="../c3ref/c_abort_rollback.html">SQLITE_IOERR_BLOCKED</a> is returned.
If the callback returns non-zero, then another attempt
is made to open the database for reading and the cycle repeats.</p>

<p>The presence of a busy handler does not guarantee that it will be invoked
when there is lock contention. If SQLite determines that invoking the busy
handler could result in a deadlock, it will go ahead and return <a href="../c3ref/c_abort.html">SQLITE_BUSY</a>
or <a href="../c3ref/c_abort_rollback.html">SQLITE_IOERR_BLOCKED</a> instead of invoking the busy handler.
Consider a scenario where one process is holding a read lock that
it is trying to promote to a reserved lock and
a second process is holding a reserved lock that it is trying
to promote to an exclusive lock.  The first process cannot proceed
because it is blocked by the second and the second process cannot
proceed because it is blocked by the first.  If both processes
invoke the busy handlers, neither will make any progress.  Therefore,
SQLite returns <a href="../c3ref/c_abort.html">SQLITE_BUSY</a> for the first process, hoping that this
will induce the first process to release its read lock and allow
the second process to proceed.</p>

<p>The default busy callback is NULL.</p>

<p>The <a href="../c3ref/c_abort.html">SQLITE_BUSY</a> error is converted to <a href="../c3ref/c_abort_rollback.html">SQLITE_IOERR_BLOCKED</a>
when SQLite is in the middle of a large transaction where all the
changes will not fit into the in-memory cache.  SQLite will
already hold a RESERVED lock on the database file, but it needs
to promote this lock to EXCLUSIVE so that it can spill cache
pages into the database file without harm to concurrent
readers.  If it is unable to promote the lock, then the in-memory
cache will be left in an inconsistent state and so the error
code is promoted from the relatively benign <a href="../c3ref/c_abort.html">SQLITE_BUSY</a> to
the more severe <a href="../c3ref/c_abort_rollback.html">SQLITE_IOERR_BLOCKED</a>.  This error code promotion
forces an automatic rollback of the changes.  See the
<a href="/cvstrac/wiki?p=CorruptionFollowingBusyError">
CorruptionFollowingBusyError</a> wiki page for a discussion of why
this is important.</p>

<p>There can only be a single busy handler defined for each
<a href="../c3ref/sqlite3.html">database connection</a>.  Setting a new busy handler clears any
previously set handler.  Note that calling <a href="../c3ref/busy_timeout.html">sqlite3_busy_timeout()</a>
will also set or clear the busy handler.</p>

<p>The busy callback should not take any actions which modify the
database connection that invoked the busy handler.  Any such actions
result in undefined behavior.</p>

<p>A busy handler must not close the database connection
or <a href="../c3ref/stmt.html">prepared statement</a> that invoked the busy handler.
</p><p>See also lists of
  <a href="objlist.html">Objects</a>,
  <a href="constlist.html">Constants</a>, and
  <a href="funclist.html">Functions</a>.</p>
